{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 20 - 即插即用估计量\n",
    " \n",
    "到目前为止，我们已经了解了如何在干预不是随机分配的情况下对我们的数据进行纠偏，这会导致混淆偏差。这有助于我们解决因果推理中的识别问题。换句话说，一旦单位是可交换的，或者 \\\\( Y(0), Y(1) \\perp X\\\\)，就可以学习干预效果。但我们还远远没有完成。\n",
    " \n",
    "识别意味着我们可以找到平均的干预效果。换句话说，我们知道一种干预的平均效果。当然，这很有用，因为它可以帮助我们决定是否应该真正实施干预。但我们想要的不止这些。我们想知道是否存在对干预反应更好或更差的单位亚组。这应该允许一个更好的策略，我们只对那些将从中受益的人进行干预。\n",
    " \n",
    " \n",
    "## 问题设置\n",
    " \n",
    "让我们回顾一下我们感兴趣的设置。鉴于潜在结果，我们可以将个体颗粒度的干预效果定义为潜在结果之间的差异。\n",
    " \n",
    "$\n",
    "\\tau_i = Y_i(1) - Y_i(0),\n",
    "$\n",
    " \n",
    "或者，连续处理情况，\\\\(\\tau_i = \\partial Y(t)\\\\)，其中 \\\\(t\\\\) 是处理变量。当然，我们永远无法观察个体的干预效果，因为我们只能看到潜在的结果之一\n",
    " \n",
    "$\n",
    "Y^{obs}_i(t)= \n",
    "\\begin{cases}\n",
    "Y_i(1), & \\text{if } t=1\\\\\n",
    "Y_i(0), & \\text{if } t=0\n",
    "\\end{cases}\n",
    "$\n",
    " \n",
    "我们可以将平均干预效果 (ATE) 定义为\n",
    " \n",
    "$\n",
    "\\tau = E[Y_i(1) - Y_i(0)] = E[\\tau_i]\n",
    "$\n",
    " \n",
    "和条件平均干预效果（CATE）为\n",
    " \n",
    "$\n",
    "\\tau(x) = E[Y_i(1) - Y_i(0)|X] = E[\\tau_i|X]\n",
    "$\n",
    " \n",
    "在本书的第一部分，我们主要关注 ATE。现在，我们对 CATE 很感兴趣。 CATE 对于个性化决策过程很有用。例如，如果您有一种药物作为干预方法 \\\\(t\\\\)，您想知道哪种类型的患者对药物的反应更高（更高的 CATE），以及是否有某些类型的患者有负面反应（类别 < 0)。\n",
    " \n",
    "我们已经了解了如何使用线性回归以及干预和特征之间的交互来估计 CATE\n",
    " \n",
    "$\n",
    "y_i = \\beta_0 + \\beta_1 t_i + \\beta_2 X_i + \\beta_3 t_i X_i + e_i。\n",
    "$\n",
    " \n",
    "如果我们估计这个模型，我们可以得到 \\\\(\\tau(x)\\\\) 的估计值\n",
    " \n",
    "$\n",
    "\\hat{\\tau}(x) = \\hat{\\beta}_1 + \\hat{\\beta}_3 t_i X_i\n",
    "$\n",
    " \n",
    "尽管如此，线性模型仍有一些缺点。主要的一个是对 \\\\(X\\\\) 的线性假设。请注意，您甚至不关心此模型上的 \\\\(\\beta_2\\\\)。但是，如果特征 \\\\(X\\\\) 与结果没有线性关系，则您对因果参数 \\\\(\\\\beta_1\\\\) 和 \\\\(\\\\beta_3\\\\) 的估计将不正确。\n",
    " \n",
    "如果我们可以用更灵活的机器学习模型代替线性模型，那就太好了。我们甚至可以将处理作为特征插入 ML 模型，例如提升树（boosted tree）或神经网络\n",
    " \n",
    "$\n",
    "y_i = M(X_i, T_i) + e_i\n",
    "$\n",
    " \n",
    "但我们如何从模型获得干预效果的估计值还不清楚，因为这个模型将输出 \\\\(\\hat{y}\\\\) 预测，而不是 \\\\(\\hat{\\tau(x)}\\\\)预测。理想情况下，我们将使用机器学习回归模型，而不是最小化结果 MSE\n",
    " \n",
    "$\n",
    "E[(Y_i - \\hat{Y}_i)^2]\n",
    "$\n",
    " \n",
    "将最小化干预效果 MSE\n",
    " \n",
    "$\n",
    "E[(\\tau(x)_i - \\hat{\\tau}(x)_i)^2] = E[(Y_i(1) - Y_i(0) - \\hat{\\tau}(x)_i)^ 2]。\n",
    "$\n",
    " \n",
    "但是，这个标准就是我们所说的不可行。同样，这里的问题是 \\\\(\\tau(x)_i\\\\) 是不可观察的，所以我们不能直接优化它。这让我们陷入了困境……让我们试着把它简化一下，也许我们可以想到一些事情。\n",
    "\n",
    "![img](./data/img/plug-and-play-estimators/infeasible.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 目标转换\n",
    " \n",
    "假设您的干预是二元的。假设您是一家投资公司，正在测试发送金融教育电子邮件的有效性。你希望这封电子邮件能让人们进行更多投资。另外，假设您进行了一项随机研究，其中 50% 的客户收到了电子邮件，而另外 50% 的客户没有收到。\n",
    " \n",
    "这是一个疯狂的想法：让我们通过将结果变量与干预相乘来转换结果变量。\n",
    " \n",
    "$\n",
    "Y^*_i = 2 Y_i * T_i - 2 Y_i*(1-T_i)\n",
    "$\n",
    " \n",
    " \n",
    "因此，如果单位被处理，您将取结果并将其乘以 2。如果未处理，您将取结果并将其乘以 -2。例如，如果您的一位客户投资了 2000,00 巴西雷亚尔并收到了电子邮件，则转换后的目标将为 4000。但是，如果他或她没有收到电子邮件，则为 -4000。\n",
    " \n",
    "这似乎很奇怪，因为您说电子邮件的效果可以是负数，但对我来说是无用的。如果我们做一些数学运算，我们可以看到，平均或预期，这个转换后的目标将是干预效果。这简直太不可思议了。我要说的是，通过应用这种有点古怪的转换，我可以估计一些我什至无法观察到的东西。\n",
    " \n",
    "要理解这一点，我们需要一些数学知识。由于随机分配，我们有 \\\\(T \\perp Y(1), Y(1)\\\\)，这是我们的老朋友。这意味着 \\\\(E[T, Y(t)]=E[T]*E[Y(t)]\\\\)，这是独立性的定义。\n",
    "\n",
    "\n",
    "另外，我们知道\n",
    "\n",
    "$\n",
    "Y_i*T_i = Y_(1)i*T_i \\text{ 和 } Y_i*(1-T_i) = Y_(0)i*T_i\n",
    "$\n",
    "\n",
    "因为干预是实现一种或其他潜在结果的原因。考虑到这一点，让我们取 \\\\(Y^*_i\\\\) 的期望值，看看我们最终会得到什么。\n",
    " \n",
    "$\n",
    "\\begin{align}\n",
    "E[Y^*_i|X_i=x] &= E[2 Y(1)_i * T_i - 2 Y(0)_i*(1-T_i)|X_i=x] \\\\\n",
    "&= 2E[Y(1)_i * T_i | X_i=x] - 2E[Y(0)_i*(1-T_i)|X_i=x]\\\\\n",
    "&= 2E[Y(1)_i| X_i=x] * E[ T_i | X_i=x] - 2E[Y(0)_i| X_i=x]*E[(1-T_i)|X_i=x] \\\\\n",
    "&= 2E[Y(1)_i| X_i=x] * 0.5 - 2E[Y(0)_i| X_i=x]*0.5 \\\\ \n",
    "&= E[Y(1)_i| X_i=x] - E[Y(0)_i| X_i=x] \\\\\n",
    "&= \\tau(x)_i\n",
    "\\end{align}\n",
    "$\n",
    " \n",
    "因此，这个看似疯狂的想法最终成为了对个体干预效果的无偏估计 \\\\(\\tau(x)_i\\\\)。现在，我们可以将不可行的优化标准替换为\n",
    " \n",
    "$\n",
    "E[(Y^*_i - \\hat{\\tau}(x)_i)^2]\n",
    "$\n",
    " \n",
    "简单来说，我们所要做的就是使用任何回归机器学习模型来预测 \\\\(Y^*_i\\\\) 并且该模型将输出干预效果预测。\n",
    " \n",
    "既然我们已经解决了简单的情况，那么更复杂的情况呢，干预不是 50% 50%，甚至不是随机分配的呢？事实证明，答案有点复杂，但并不多。首先，如果我们没有随机分配，我们至少需要条件独立 \\\\(T \\perp Y(1), Y(1) | X\\\\)。也就是说，控制 \\\\(X\\\\), \\\\(T\\\\) 与随机一样好。这样，我们可以将转换后的目标泛化为\n",
    " \n",
    "$\n",
    "Y^*_i = Y_i * \\dfrac{T_i - e(X_i)}{e(X_i)(1-e(X_i))}\n",
    "$\n",
    " \n",
    "其中 \\\\(e(X_i)\\\\) 是倾向得分。因此，如果干预不是 50% 50%，而是以不同的概率 \\\\(p\\\\) 随机化，您所要做的就是将上述公式中的倾向得分替换为 \\\\(p\\\\)。如果干预不是随机的，那么您必须使用存储或估计的倾向得分。\n",
    " \n",
    "如果您对此进行预期，您会发现它也与干预效果相匹配。证明留给读者作为练习。开个玩笑，就在这里。这有点麻烦，所以请随意跳过它。\n",
    " \n",
    "$\n",
    "\\begin{align}\n",
    "E[Y^*_i|X_i=x] &= E\\big[Y_i * \\dfrac{T_i - e(X_i)}{e(X_i)(1-e(X_i))}|X_i=x\\big] \\\\\n",
    "&= E\\big[Y_i T_i * \\dfrac{T_i - e(X_i)}{e(X_i)(1-e(X_i))} + Y_i (1-T_i) * \\dfrac{T_i - e(X_i)}{e(X_i)(1-e(X_i))}|X_i=x\\big]\\\\\n",
    "&= E\\big[Y(1)_i * \\dfrac{T_i(1 - e(X_i))}{e(X_i)(1-e(X_i))} | X_i=x\\big] - E\\big[Y(0)_i * \\dfrac{(1-T_i)e(X_i)}{e(X_i)(1-e(X_i))}|X_i=x\\big]\\\\\n",
    "&= \\dfrac{1}{e(X_i)} E[Y(1)_i * T_i|X_i=x] - \\dfrac{1}{1-e(X_i)} E[Y(0)_i * (1-T_i)| X_i=x]\\\\\n",
    "&= \\dfrac{1}{e(X_i)} E[Y(1)_i|X_i=x] * E[T_i|X_i=x] - \\dfrac{1}{1-e(X_i)} E[Y(0)_i|X_i=x] * E[(1-T_i)| X_i=x]\\\\\n",
    "&= E[Y(1)_i|X_i=x] - E[Y(0)_i|X_i=x]\\\\\n",
    "&= \\tau(x)_i\n",
    "\\end{align}\n",
    "$\n",
    " \n",
    "与往常一样，我认为这将通过一个示例变得更加具体。同样，考虑一下我们发送的试图让人们进行更多投资的投资电子邮件。结果变量二进制（投资与未投资）“转换”。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "import seaborn as sns\n",
    "from nb21 import cumulative_gain, elast"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "      <th>income</th>\n",
       "      <th>insurance</th>\n",
       "      <th>invested</th>\n",
       "      <th>em1</th>\n",
       "      <th>em2</th>\n",
       "      <th>em3</th>\n",
       "      <th>converted</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>44.1</td>\n",
       "      <td>5483.80</td>\n",
       "      <td>6155.29</td>\n",
       "      <td>14294.81</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>39.8</td>\n",
       "      <td>2737.92</td>\n",
       "      <td>50069.40</td>\n",
       "      <td>7468.15</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>49.0</td>\n",
       "      <td>2712.51</td>\n",
       "      <td>5707.08</td>\n",
       "      <td>5095.65</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>39.7</td>\n",
       "      <td>2326.37</td>\n",
       "      <td>15657.97</td>\n",
       "      <td>6345.20</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>35.3</td>\n",
       "      <td>2787.26</td>\n",
       "      <td>27074.44</td>\n",
       "      <td>14114.86</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    age   income  insurance  invested  em1  em2  em3  converted\n",
       "0  44.1  5483.80    6155.29  14294.81    0    1    1          0\n",
       "1  39.8  2737.92   50069.40   7468.15    1    0    0          0\n",
       "2  49.0  2712.51    5707.08   5095.65    1    0    1          1\n",
       "3  39.7  2326.37   15657.97   6345.20    1    1    1          0\n",
       "4  35.3  2787.26   27074.44  14114.86    1    1    1          0"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "email = pd.read_csv(\"./data/invest_email_rnd.csv\")\n",
    "email.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们的目标是个性化之一。 让我们关注 email-1。 我们希望仅将其发送给那些对其反应更好的客户。 换句话说，我们希望估计 email-1 的条件平均处理效果\n",
    " \n",
    "$\n",
    "E[Converted(1)_i - Converted(0)_i|X_i=x] = \\tau(x)_i\n",
    "$\n",
    " \n",
    "这样我们就可以定位那些对电子邮件反应最好的客户（更高的 CATE）\n",
    " \n",
    "但首先，让我们将数据集分解为训练集和验证集。 我们将在一组上估计 \\\\(\\tau(x)_i\\\\) 并评估另一组的估计。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(9000, 8) (6000, 8)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "np.random.seed(123)\n",
    "train, test = train_test_split(email, test_size=0.4)\n",
    "print(train.shape, test.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，我们将应用我们刚刚学习的目标转换。 由于电子邮件是随机分配的（尽管不是在 50% 50% 的基础上），我们不需要担心倾向得分。 相反，它是恒定的并且等于干预概率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "y = \"converted\"\n",
    "T = \"em1\"\n",
    "X = [\"age\", \"income\", \"insurance\", \"invested\"]\n",
    "\n",
    "ps = train[T].mean()\n",
    "\n",
    "y_star_train = train[y] * (train[T] - ps)/(ps*(1-ps))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用转换后的目标，我们可以选择任何 ML 回归算法来预测它。 让我们在这里使用提升树（boosted tree）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'np' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_13460\\368639505.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mlightgbm\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mLGBMRegressor\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mseed\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m123\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      4\u001b[0m \u001b[0mcate_learner\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mLGBMRegressor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmax_depth\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmin_child_samples\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m300\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnum_leaves\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[0mcate_learner\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtrain\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mX\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my_star_train\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m;\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'np' is not defined"
     ]
    }
   ],
   "source": [
    "from lightgbm import LGBMRegressor\n",
    "\n",
    "np.random.seed(123)\n",
    "cate_learner = LGBMRegressor(max_depth=3, min_child_samples=300, num_leaves=5)\n",
    "cate_learner.fit(train[X], y_star_train);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "该模型现在可以估计 \\\\(\\tau(x)_i\\\\)。 换句话说，它输出的是 \\\\(\\hat{\\tau}(x)_i\\\\)。 例如，如果我们对测试集进行预测，我们会看到某些单元的 CATE 比其他单元高。 例如，客户 6958 的 CATE 为 0.1，这意味着如果我们向该客户发送电子邮件，他或她购买我们的投资产品的概率预计会增加 0.1。 相反，对于客户 3903，预计购买该产品的概率仅增加 0.04。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "      <th>income</th>\n",
       "      <th>insurance</th>\n",
       "      <th>invested</th>\n",
       "      <th>em1</th>\n",
       "      <th>em2</th>\n",
       "      <th>em3</th>\n",
       "      <th>converted</th>\n",
       "      <th>cate</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>6958</th>\n",
       "      <td>40.9</td>\n",
       "      <td>4486.14</td>\n",
       "      <td>37320.33</td>\n",
       "      <td>12559.25</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0.105665</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7534</th>\n",
       "      <td>42.6</td>\n",
       "      <td>6386.19</td>\n",
       "      <td>13270.47</td>\n",
       "      <td>29114.42</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0.121922</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2975</th>\n",
       "      <td>47.6</td>\n",
       "      <td>1900.26</td>\n",
       "      <td>25588.72</td>\n",
       "      <td>2420.39</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0.034161</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3903</th>\n",
       "      <td>41.0</td>\n",
       "      <td>5802.19</td>\n",
       "      <td>57087.37</td>\n",
       "      <td>20182.20</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.046805</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8437</th>\n",
       "      <td>49.1</td>\n",
       "      <td>2202.96</td>\n",
       "      <td>5050.81</td>\n",
       "      <td>9245.88</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>-0.009099</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       age   income  insurance  invested  em1  em2  em3  converted      cate\n",
       "6958  40.9  4486.14   37320.33  12559.25    0    0    1          0  0.105665\n",
       "7534  42.6  6386.19   13270.47  29114.42    0    0    1          0  0.121922\n",
       "2975  47.6  1900.26   25588.72   2420.39    0    0    1          0  0.034161\n",
       "3903  41.0  5802.19   57087.37  20182.20    1    0    1          1  0.046805\n",
       "8437  49.1  2202.96    5050.81   9245.88    1    0    1          0 -0.009099"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_pred = test.assign(cate=cate_learner.predict(test[X]))\n",
    "test_pred.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为了评估这个模型有多好，我们可以展示训练集和测试集的累积增益曲线。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "gain_curve_test = cumulative_gain(test_pred, \"cate\", y=\"converted\", t=\"em1\")\n",
    "gain_curve_train = cumulative_gain(train.assign(cate=cate_learner.predict(train[X])), \"cate\", y=\"converted\", t=\"em1\")\n",
    "plt.plot(gain_curve_test, color=\"C0\", label=\"Test\")\n",
    "plt.plot(gain_curve_train, color=\"C1\", label=\"Train\")\n",
    "plt.plot([0, 100], [0, elast(test, \"converted\", \"em1\")], linestyle=\"--\", color=\"black\", label=\"Baseline\")\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "正如我们所看到的，这个即插即用的估计器在测试集上比随机的要好。 尽管如此，它看起来还是过拟合了很多，因为在训练集上的表现比在测试集上的表现要好得多。\n",
    " \n",
    "这实际上是这种目标转换技术的最大缺点之一。 使用此目标转换，您确实获得了很多简单性，因为您只需转换目标并使用任何 ML 估计器来预测异构干预效果。 它的代价是你会得到很多差异。 这是因为转换后的目标是对个体干预效果的非常嘈杂的估计，并且该方差会转移到您的估计中。 如果您没有大量数据，这将是一个大问题，但在处理超过 1MM 样本的大数据应用程序中应该问题不大。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 连续型干预变量案例\n",
    "\n",
    "![img](./data/img/plug-and-play-estimators/second-estimator.png)\n",
    "\n",
    "目标转换方法的另一个明显缺点是它仅适用于离散或二元处理。这是你在因果推理文献中经常看到的东西。大多数研究都是针对二元干预案例进行的，但您找不到很多关于连续干预的研究。这让我很困扰，因为在这个行业中，持续干预无处不在，主要是您需要优化的价格形式。因此，即使我找不到任何关于持续干预的目标转换的信息，我还是想出了一些在实践中有效的方法。请记住，我没有围绕它进行的超级可靠的计量经济学研究。\n",
    " \n",
    "为了激发它，让我们回到冰淇淋销售的例子。在那里，我们的任务是估计价格的需求弹性，以便我们可以更好地设定冰淇淋价格以优化我们的收入。回想一下，数据集中的事件样本是一天，我们希望知道人们何时对价格上涨不那么敏感。另外，回想一下，价格在这个数据集中是随机分配的，这意味着我们不需要担心混淆偏差。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>temp</th>\n",
       "      <th>weekday</th>\n",
       "      <th>cost</th>\n",
       "      <th>price</th>\n",
       "      <th>sales</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>25.8</td>\n",
       "      <td>1</td>\n",
       "      <td>0.3</td>\n",
       "      <td>7</td>\n",
       "      <td>230</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>22.7</td>\n",
       "      <td>3</td>\n",
       "      <td>0.5</td>\n",
       "      <td>4</td>\n",
       "      <td>190</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>33.7</td>\n",
       "      <td>7</td>\n",
       "      <td>1.0</td>\n",
       "      <td>5</td>\n",
       "      <td>237</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>23.0</td>\n",
       "      <td>4</td>\n",
       "      <td>0.5</td>\n",
       "      <td>5</td>\n",
       "      <td>193</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24.4</td>\n",
       "      <td>1</td>\n",
       "      <td>1.0</td>\n",
       "      <td>3</td>\n",
       "      <td>252</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   temp  weekday  cost  price  sales\n",
       "0  25.8        1   0.3      7    230\n",
       "1  22.7        3   0.5      4    190\n",
       "2  33.7        7   1.0      5    237\n",
       "3  23.0        4   0.5      5    193\n",
       "4  24.4        1   1.0      3    252"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prices_rnd = pd.read_csv(\"./data/ice_cream_sales_rnd.csv\")\n",
    "prices_rnd.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和之前一样，让我们先把数据分为训练和测试两个集合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((3500, 5), (1500, 5))"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.seed(123)\n",
    "train, test = train_test_split(prices_rnd, test_size=0.3)\n",
    "train.shape, test.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "现在是我们需要一点创造力的地方。对于离散情况，条件平均处理效果由当我们从未处理到处理时结果变化多少给出，以单位特征 \\\\(X\\\\) 为条件。\n",
    " \n",
    "$\n",
    "\\tau(x) = E[Y_i(1) - Y_i(0)|X] = E[\\tau_i|X]\n",
    "$\n",
    " \n",
    "简而言之，这是估计处理对不同单元配置文件的影响，其中配置文件是使用特征 \\\\(X\\\\) 定义的。对于连续的情况，我们没有那个开关。单元未经处理或未经处理。相反，它们都经过处理，但强度不同。因此，我们不能谈论给予干预的效果。相反，我们需要从增加干预的角度说话。换句话说，我们想知道如果我们增加一定量的干预，结果会如何变化。这就像估计结果函数 \\\\(Y\\\\) 对干预 \\\\(t\\\\) 的偏导数。并且因为我们希望知道对于每个组（CATE，而不是 ATE），我们以特征 \\\\(X\\\\) 为条件\n",
    " \n",
    "$\n",
    "\\tau(x) = E[\\partial Y_i(t)|X] = E[\\tau_i|X]\n",
    "$\n",
    " \n",
    "我们如何估计呢？首先，让我们考虑一个简单的情况，其中结果与干预呈线性关系。假设您有两种类型的日子：炎热的日子（黄色）和寒冷的日子（蓝色）。在寒冷的日子里，人们对价格上涨更加敏感。此外，随着价格上涨，需求线性下降。\n",
    " \n",
    "![img](./data/img/plug-and-play-estimators/linear-case.png)\n",
    " \n",
    "在这种情况下，CATE 将是每条需求线的斜率。这些斜率将告诉我们，如果我们将价格提高任何数量，需求会下降多少。如果这种关系确实是线性的，我们可以分别用简单线性回归估计热天和冷天的系数来估计这些弹性。\n",
    " \n",
    "$$\n",
    "\\hat{\\tau(x)} = Cov(Y_i, T_i)/Var(T_i) = \\dfrac{\\sum(Y_i- \\bar{Y})(T_i - \\bar{T})}{\\sum ( T_i - \\bar{T})^2}\n",
    "$$\n",
    " \n",
    "我们可以从这个估算器中得到启发，思考一个单独的单元会是什么样子。换句话说，如果我们在那里有同样的东西，为每一天定义。在我的脑海里，它会是这样的："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\n",
    "Y^*_i = (Y_i- \\bar{Y})\\dfrac{(T_i - \\bar{T})}{\\sigma^2_T}\n",
    "$\n",
    " \n",
    "用简单的英语来说，我们将通过从中减去平均值来转换原始目标，然后将其乘以处理，我们也从中减去了平均值。最后，我们将其除以处理方差。唉，我们有一个针对连续情况的目标转换。\n",
    "\n",
    "![img](./data/img/plug-and-play-estimators/genious.jpeg)\n",
    "\n",
    "现在的问题是：它有效吗？事实上，它确实如此，我们可以通过一个类似的证明来证明它为什么起作用，就像我们在二进制案例中所做的那样。首先，让我们打电话\n",
    " \n",
    "$\n",
    "V_i = \\dfrac{(T_i - \\bar{T})}{\\sigma^2_T}\n",
    "$\n",
    " \n",
    "注意 \\\\(E[V_i|X_i=x]=0\\\\) 因为在随机分配下 \\\\(E[T_i|X_i=x]=\\bar{T}\\\\)。换句话说，对于 X 的每个区域，\\\\(E[T_i]=\\bar{T}\\\\)。还有 \\\\(E[T_i V_i | X_i=x]=1\\\\) 因为 \\\\(E[T_i(T_i - \\bar{T})|X_i=x] = E[(T_i - \\bar{T} )^2|X_i=x]\\\\)，即处理方差。最后，在条件独立（我们在随机处理分配情况下免费获得）下，\\\\(E[T_i e_i | X_i=x] = E[T_i | X_i=x] E[e_i | X_i=x]\\\\) 。\n",
    " \n",
    "为了证明这个目标转换是有效的，我们需要记住我们正在估计一个局部线性模型的参数\n",
    " \n",
    "$\n",
    "Y_i = \\alpha + \\beta T_i + e_i | X_i=x\n",
    "$\n",
    " \n",
    "在我们的示例中，这些将是炎热和寒冷日子的线性模型。在这里，我们对 \\\\(\\beta\\\\) 参数感兴趣，这是我们的条件弹性或 CATE。有了这一切，我们可以证明\n",
    " \n",
    "$\n",
    "\\begin{align}\n",
    "E[Y^*_i|X_i=X] &= E[(Y_i-\\bar{Y})V_i | X_i=x] \\\\\n",
    "&= E[(\\alpha + \\beta T_i + e_i - \\bar{Y})V_i | X_i=x] \\\\\n",
    "&= \\alpha E[V_i | X_i=x] + \\beta E[T_i V_i | X_i=x] + E[e_i V_i | X_i=x] \\\\\n",
    "&= \\beta + E[e_i V_i | X_i=x] \\\\\n",
    "&= \\beta = \\tau(x)\n",
    "\\end{align}\n",
    "$\n",
    " \n",
    "请记住，这仅在随机干预时有效。对于非随机处理，我们必须将 \\\\(\\bar{T}\\\\) 替换为 \\\\(M(X_i)\\\\)，其中 \\\\(M\\\\) 是一个估计 \\\\(E[ T_i|X_i=x]\\\\)。\n",
    " \n",
    "$\n",
    "Y^*_i = (Y_i- \\bar{Y})\\dfrac{(T_i - M(T_i))}{(T_i - M(T_i))^2}\n",
    "$\n",
    " \n",
    "这将确保第三行中的术语 \\\\(\\alpha E[V_i | X_i=x]\\\\) 消失为零，并且术语 \\\\(E[T_i V_i | X_i=x]\\\\) 消失到 1。请注意，如果您只想根据干预效果对单位进行排序，实际上并不需要 \\\\(E[T_i V_i | X_i=x]\\\\) 去 1。换句话说，如果您只想知道需求在哪几天对价格上涨更敏感，但您不需要知道多少，那么 \\\\(\\beta\\\\) 估计值是否按比例缩放并不重要上或下。如果是这种情况，您可以省略分母。\n",
    " \n",
    "$\n",
    "Y^*_i = (Y_i- \\bar{Y})(T_i - M(T_i))\n",
    "$\n",
    " \n",
    "如果所有这些数学看起来很烦人，请不要担心。代码其实很简单。再一次，我们用上面看到的公式转换我们的训练目标。在这里，我们有随机的处理分配，所以我们不需要建立一个预测价格的模型。我也省略了分母，因为这里我只关心排序处理效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_star_cont = (train[\"price\"] - train[\"price\"].mean()\n",
    "               *train[\"sales\"] - train[\"sales\"].mean())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后，就像以前一样，我们拟合回归 ML 模型来预测该目标。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>temp</th>\n",
       "      <th>weekday</th>\n",
       "      <th>cost</th>\n",
       "      <th>price</th>\n",
       "      <th>sales</th>\n",
       "      <th>cate</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2815</th>\n",
       "      <td>15.7</td>\n",
       "      <td>4</td>\n",
       "      <td>1.5</td>\n",
       "      <td>3</td>\n",
       "      <td>187</td>\n",
       "      <td>-1395.956278</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>257</th>\n",
       "      <td>29.4</td>\n",
       "      <td>3</td>\n",
       "      <td>1.0</td>\n",
       "      <td>3</td>\n",
       "      <td>209</td>\n",
       "      <td>-1607.400415</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2585</th>\n",
       "      <td>24.6</td>\n",
       "      <td>6</td>\n",
       "      <td>1.0</td>\n",
       "      <td>10</td>\n",
       "      <td>197</td>\n",
       "      <td>-1497.197402</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3260</th>\n",
       "      <td>20.2</td>\n",
       "      <td>1</td>\n",
       "      <td>0.5</td>\n",
       "      <td>4</td>\n",
       "      <td>246</td>\n",
       "      <td>-1629.798111</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1999</th>\n",
       "      <td>10.0</td>\n",
       "      <td>4</td>\n",
       "      <td>0.5</td>\n",
       "      <td>10</td>\n",
       "      <td>139</td>\n",
       "      <td>-1333.690544</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      temp  weekday  cost  price  sales         cate\n",
       "2815  15.7        4   1.5      3    187 -1395.956278\n",
       "257   29.4        3   1.0      3    209 -1607.400415\n",
       "2585  24.6        6   1.0     10    197 -1497.197402\n",
       "3260  20.2        1   0.5      4    246 -1629.798111\n",
       "1999  10.0        4   0.5     10    139 -1333.690544"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cate_learner = LGBMRegressor(max_depth=3, min_child_samples=300, num_leaves=5)\n",
    "\n",
    "np.random.seed(123)\n",
    "cate_learner.fit(train[[\"temp\", \"weekday\", \"cost\"]], y_star_cont)\n",
    "\n",
    "cate_test_transf_y = cate_learner.predict(test[[\"temp\", \"weekday\", \"cost\"]])\n",
    "\n",
    "test_pred = test.assign(cate=cate_test_transf_y)\n",
    "test_pred.sample(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这一次，CATE 的解释是不直观的。 由于我们已经从目标转换中删除了分母，所以我们看到的这个 CATE 是由 \\\\(Var(X)\\\\) 缩放的。 然而，这个预测仍然应该很好地排序干预效果。 为了看到这一点，我们可以使用累积增益曲线，就像我们之前所做的那样。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "gain_curve_test = cumulative_gain(test.assign(cate=cate_test_transf_y),\n",
    "                                \"cate\", y=\"sales\", t=\"price\")\n",
    "\n",
    "gain_curve_train = cumulative_gain(train.assign(cate=cate_learner.predict(train[[\"temp\", \"weekday\", \"cost\"]])),\n",
    "                                   \"cate\", y=\"sales\", t=\"price\")\n",
    "\n",
    "\n",
    "plt.plot(gain_curve_test, label=\"Test\")\n",
    "plt.plot(gain_curve_train, label=\"Train\")\n",
    "plt.plot([0, 100], [0, elast(test, \"sales\", \"price\")], linestyle=\"--\", color=\"black\", label=\"Taseline\")\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于这些数据，看起来具有转换目标的模型比随机模型要好得多。不仅如此，训练和测试结果非常接近，因此这里的方差不是问题。但这只是这个数据集的一个特征。如果您还记得，当我们探索二元处理案例时，情况并非如此。在那里，模型的表现不是很好。\n",
    " \n",
    "### 非线性处理效果\n",
    " \n",
    "谈到了连续案例，我们需要处理的房间里还有一头大象。我们假设干预效果呈线性关系。然而，这很少是一个合理的假设。通常，干预效果以一种或另一种形式饱和。在我们的示例中，可以合理地认为，在价格上涨的第一个单位时需求会下降得更快，但随后会下降得更慢。\n",
    " \n",
    "![img](./data/img/plug-and-play-estimators/non-linear-case.png)\n",
    " \n",
    "这里的问题是**弹性或干预效果随干预本身而变化**。在我们的示例中，干预效果在曲线开始时更加强烈，而随着价格的上涨而减弱。同样，假设您有两种类型的日子：炎热的日子（黄色）和寒冷的日子（蓝色），我们想用因果模型区分这两者。问题是因果模型应该预测弹性，但在非线性情况下，如果我们查看曲线中不同的价格点（右图），炎热和寒冷天的弹性可能相同。\n",
    " \n",
    "解决这个问题没有简单的方法，我承认我仍在研究什么最有效。目前，我所做的事情是尝试考虑干预效果的函数形式，并以某种方式将其线性化。例如，需求通常具有以下函数形式，其中较高的 \\\\(\\alpha\\\\)s 意味着随着价格的每次上涨，需求下降得更快\n",
    " \n",
    "$\n",
    "D_i = \\dfrac{1}{P_i^{\\alpha}}\n",
    "$\n",
    "\n",
    "所以，如果我对需求 \\\\(Y\\\\) 和价格 \\\\(T\\\\) 都应用对数转换，我应该得到线性的东西。\n",
    "\n",
    "$\n",
    "\\begin{align}\n",
    "log(D)_i &= log\\bigg(\\dfrac{1}{P_i^{\\alpha}}\\bigg) \\\\\n",
    "&= log(1) - log(P_i^{\\alpha}) \\\\\n",
    "&= log(1) - log(P_i^{\\alpha}) \\\\\n",
    "&= - \\alpha * log(P_i) \\\\\n",
    "\\end{align}\n",
    "$\n",
    " \n",
    "线性化并不是那么容易做到的，因为它需要一些思考。但你也可以尝试一些东西，看看什么效果最好。通常，对数和平方根之类的东西会有所帮助。\n",
    " \n",
    "## 关键思想\n",
    "\n",
    "我们现在正朝着使用机器学习模型估计条件平均干预效果的方向发展。这样做的最大挑战是使预测模型适应估计因果效应的模型。另一种思考方式是，预测模型专注于将结果 Y 估计为特征 X 的函数，可能还有干预 T \\\\(Y = M(X, T) \\\\) 而因果模型需要估计这个输出函数在处理 \\\\(\\partial Y = \\partial M(X, T) \\\\) 上。这不是简单方法就可以解决的，因为虽然我们确实观察到了结果 Y，但我们不能观察到 \\\\(\\partial Y\\\\)，至少在个体样本层面上不能。因此，在为我们的模型设计目标函数时，我们需要具有创造性。\n",
    " \n",
    "在这里，我们看到了一种非常简单的目标转换技术。这个想法是将原始目标 Y 与干预 T 结合起来，形成一个转换后的目标，期望它等于 CATE。有了这个新目标，我们可以插入任何预测性 ML 模型来估计它，然后模型预测将是 CATE 估计。附带说明一下，除了目标转换之外，此方法也称为 **F-Learner**。\n",
    " \n",
    "尽管如此简单，但也需要付出代价。转换后的目标是对个体干预效果的非常嘈杂的估计，并且该噪声将以方差的形式转移到模型估计中。这使得目标转换更适合大数据应用，在这些场景中，由于样本量很大，方差不是个大问题。目标转换方法的另一个缺点是它仅针对二元或分类处理定义。我们尽最大努力提出该方法的连续版本，甚至最终得出了一些似乎可行的方法，但到目前为止，还没有可靠的理论框架来支持它。\n",
    " \n",
    "最后，我们以对非线性干预效果及其带来的挑战的讨论结束。也就是说，当干预效果随干预本身而变化时，我们可能会错误地认为单位具有相同的干预反应曲线，因为它们对干预的反应相同，但实际上它们只是接受了不同的干预量。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
